﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using IdeaNMR.Web.Core;
using System.Text.RegularExpressions;
using System.Web.UI.WebControls;
using System.Text;

namespace IdeaNMR.Web
{
    public abstract class ListBaseObjects_BaseTable<TObj> : System.Web.UI.UserControl
        where TObj : BaseObject
    {
        protected class Item
        {
            public TObj Obj { get; set; }
        }

        #region Page Controls Declarations
        protected global::System.Web.UI.WebControls.DataPager TopDataPager, BottomDataPager;
        protected global::System.Web.UI.WebControls.TextBox SearchBox;
        protected global::System.Web.UI.WebControls.CheckBox IncludePrivateCheckBox, IncludePublicCheckBox;

        protected global::System.Web.UI.WebControls.ListView ContentList;
        // Only when ListView gets its data from LinqDataSource it can be automatically sorted.
        // If you assign ListView.DataSource property manually from code behind directly to ListView - you have to
        // handle sorting event manually
        protected global::System.Web.UI.WebControls.LinqDataSource DataSource;
        #endregion

        /// <summary>
        /// A CssClass that will be added as prefix to every internal control that has CssClass specified.
        /// </summary>
        public string CssClass { get; set; }

        /// <summary>
        /// If true, than on clicking the row a Selected event is fired.
        /// Also visual effects are added to the table.
        /// </summary>
        [System.ComponentModel.DefaultValue(false)]
        public bool Selectable
        {
            get
            {
                bool? res = ViewState["Selectable"] as bool?;
                if (res.HasValue) return res.Value;
                else return false;
            }
            set
            { ViewState["Selectable"] = value; }
        }

        /// <summary>
        /// Number of items on one page
        /// </summary>
        [System.ComponentModel.DefaultValue(15)]
        public int PageSize
        {
            get
            {
                if (ViewState["PageSize"] is int)
                    return (int)ViewState["PageSize"];
                else return 15;
            }
            set { ViewState["PageSize"] = value; }
        }

        /// <summary>
        /// Set tu specify if you want to see Private Items in the list
        /// Default value is true
        /// </summary>
        [System.ComponentModel.DefaultValue(true)]
        private bool IncludePrivate
        {
            get { return IncludePrivateCheckBox.Checked; }
            set { IncludePrivateCheckBox.Checked = value; }
        }

        /// <summary>
        /// Set to specify if you want to see Public Items in the list
        /// Default value is true
        /// </summary>
        [System.ComponentModel.DefaultValue(true)]
        private bool IncludePublic
        {
            get { return IncludePublicCheckBox.Checked; }
            set { IncludePublicCheckBox.Checked = value; }
        }

        /// <summary>
        /// The search string
        /// </summary>
        /// Default value is string.Empty
        protected string[] SearchTerms
        {
            get
            {
                string text = SearchBox.Text;
                //  string text = ((TextBox)ContentListView.FindControl("SearchBox")).Text;
                if (!string.IsNullOrEmpty(text))
                {
                    return text.ToLowerInvariant().Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                }
                else return new string[0];
            }
            set { SearchBox.Text = string.Join(" ", value); }
        }

        protected string SearchRegEx
        {
            get { return @"^" + string.Join("|^", this.SearchTerms).Replace(".", @"\."); }
        }

        /// <summary>
        /// The event is fired when user clicks on an entry in a table and Selectable is true.
        /// </summary>
        public event ItemSelectedEventHandler Selected;

        public void Refresh()
        {
            this._RawData = LoadRawData();
            ContentList.DataBind();
        }

        private Item[] _RawData;
        protected Item[] RawData
        {
            get
            {
                if (this._RawData == null) this._RawData = LoadRawData();
                return this._RawData;
            }
        }
        protected abstract Item[] LoadRawData();
        protected virtual Item[] FilterRawData()
        {
            IEnumerable<Item> result = this.RawData;

            // Check whether to include private or public items
            result = from r in result
                     where
                        !r.Obj.IsDraft &&
                        (r.Obj.IsPrivate ? this.IncludePrivate : this.IncludePublic)
                     select r;

            // Check for search terms
            if (this.SearchTerms.Length > 0)
            {
                result = from r in result
                         where
                              Regex.IsMatch(r.Obj.Name.ToLowerInvariant(), this.SearchRegEx) ||  // Name
                              r.Obj.Datetime.ToString().ToLowerInvariant().Split(' ').Any(d => Regex.IsMatch(d, this.SearchRegEx)) // Datetime
                         select r;

            }
            return result.ToArray();
        }

        private string IncludePrivateCookie
        {
            get
            {
                return typeof(TObj).ToString() + "_IncludePrivate";
            }
        }
        private string IncludePublicCookie
        { 
        get
            {
                return typeof(TObj).ToString() + "_IncludePublic";
            }
        }

        #region Page Life Cycle
        protected void Page_Init(object sender, EventArgs e)
        {
            HttpCookie InclPrivate = Request.Cookies[this.IncludePrivateCookie];
            if (InclPrivate != null) this.IncludePrivate = bool.Parse(InclPrivate.Value);
            HttpCookie InclPublic = Request.Cookies[this.IncludePublicCookie];
            if (InclPublic != null) this.IncludePublic = bool.Parse(InclPublic.Value);
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!Page.IsPostBack)
            {
                TopDataPager.PageSize = BottomDataPager.PageSize = this.PageSize;
            }
        }
        #region Control Events
        protected void DataSource_OnSelect(object sender, LinqDataSourceSelectEventArgs e)
        {
            e.Result = this.FilterRawData();
        }
        protected void Item_Command(object sender, CommandEventArgs e)
        {
            if (e.CommandName != "PickItem") return;
            Guid target = new Guid(e.CommandArgument.ToString());
            TObj o = this.RawData.Where(b => b.Obj.Id == target).Single().Obj;
            if (o == null) return;
            if (this.Selected != null) Selected(this, new ItemSelectedCommandEventArgs(o));
        }
        protected void ContentListView_ItemDataBound(object sender, ListViewItemEventArgs e)
        {
            if (e.Item.ItemType == ListViewItemType.DataItem && this.Selectable)
            {
                Button btn = e.Item.FindControl("InvisibleCommandButton") as Button;
                string script = this.Page.ClientScript.GetPostBackClientHyperlink(btn, string.Empty, false);
                //string script = this.ClientScript.GetPostBackClientHyperlink(btn, "", true);
                Panel p = e.Item.FindControl("ItemPanel") as Panel;
                p.Attributes.Add("onclick", script);
            }
        }
        /// <summary>
        /// When Search button clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void SearchButton_Click(object sender, EventArgs e)
        {
            ContentList.DataBind();
            SearchBox.Focus();
        }
        /// <summary>
        /// When user check checkboxes include public and include private.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void SelectionControlState_Changed(object sender, EventArgs e)
        {
            ContentList.DataBind();
        }
        /// <summary>
        /// When refresh button clicked.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        protected void Refresh_Click(object sender, EventArgs e)
        {
            Refresh();
        }
        #endregion

        protected virtual void Page_PreRender(object sender, EventArgs e)
        {
            Response.Cookies[this.IncludePrivateCookie].Value = this.IncludePrivate.ToString();
            Response.Cookies[this.IncludePrivateCookie].Expires = DateTime.Now.AddDays(30);
            Response.Cookies[this.IncludePublicCookie].Value = this.IncludePublic.ToString();
            Response.Cookies[this.IncludePublicCookie].Expires = DateTime.Now.AddDays(30);

            ContentList.DataBind();
        }
        #endregion

        protected string CreateCssClass(object obj)
        {
            BaseObject o = (BaseObject)obj;
            return this.CssClass + " Item " + (this.Selectable ? " Selectable" : string.Empty) + (o.IsPrivate ? " PrivateColor" : " PublicColor");
        }
    }


    public delegate void ItemSelectedEventHandler(object sender, ItemSelectedCommandEventArgs e);
    public class ItemSelectedCommandEventArgs : EventArgs
    {
        public BaseObject SelectedItem
        {
            get;
            private set;
        }

        public ItemSelectedCommandEventArgs(BaseObject o)
        {
            this.SelectedItem = o;
        }
    }
}